package com.df.ez_game.server.logic;

import com.df.ez_game.server.NettyHeartBeatHandler;
import com.df.ez_game.server.NettyServerSettings;
import com.df.ez_game.server.ServerNode;
import com.df.ez_game.tools.OsHelper;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Data
public class StandAloneWebsocketNettyServerSettings implements NettyServerSettings {
    private Integer port;
    private ServerNode serverNode;
    private String path;
    @Override
    public EventLoopGroup boosGroup() {
//        int size = Runtime.getRuntime().availableProcessors();
//        if(OsHelper.isWindow()){
//            return new NioEventLoopGroup(size, new ThreadFactory() {
//                @Override
//                public Thread newThread(Runnable r) {
//                    Thread thread = new Thread(r,"gateway-boss-thread");
//                    thread.setDaemon(true);
//                    return thread;
//                }
//            });
//        }
        //TODO 线程的名字自定义
        return OsHelper.getGroupByOs();
    }

    @Override
    public EventLoopGroup worGroup() {
        return OsHelper.getGroupByOs();
    }

    @Override
    public Class<? extends ServerChannel> channel() {
        return NioServerSocketChannel.class;
    }

    @Override
    public void settingServerBootStrap(ServerBootstrap bootstrap) {
        LogicServerNode lsn = (LogicServerNode) serverNode;
        LogicSettings settings = lsn.getSettings();
        if(settings.getHeartBeatCallBack()!=null){
            int readIdleTime = settings.getReadIdleTime();
            if(readIdleTime<=0){
                log.error("读空闲时间配置值小于等于0，使用默认值 30");
                settings.setReadIdleTime(30);
            }
            int writeIdleTime = settings.getWriteIdleTime();
            if(writeIdleTime<=0){
                log.error("写空闲时间配置值小于等于0，使用默认值 30");
                settings.setWriteIdleTime(30);
            }
            int allIdleTime = settings.getAllIdleTime();
            if(allIdleTime<=0){
                log.error("读写空闲时间配置值小于等于0，使用默认值 60");
                settings.setAllIdleTime(60);
            }
        }
        bootstrap.channel( channel())
                .option(ChannelOption.SO_BACKLOG, 1024)
                //buffer配置
                .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator())
                //池化处理
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                //发送接收缓冲器
                .childOption(ChannelOption.SO_SNDBUF, 2048 * 1024)
                .childOption(ChannelOption.SO_RCVBUF, 512 * 1024)
                //TCP处理
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                //重用地址
                .childOption(ChannelOption.SO_REUSEADDR, true)

                .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
                        new WriteBufferWaterMark(512 * 1024, 2048 * 1024));

        //设置handler
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                ChannelPipeline pipeline = socketChannel.pipeline();
                //协议编解码
                //http编解码器
                pipeline.addLast("http-codec", new HttpServerCodec());
                // 对 httpMessage 进行聚合，聚合成 FullHttpRequest 或 FullHttpResponse
                // 几乎在 netty 编程中, 都会使用该 Handler
                // 支持参数对象解析，比如 POST 参数，设置聚合内容的最大长度
                pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
                //对大数据流的支持
                pipeline.addLast(new ChunkedWriteHandler());
//                pipeline.addLast(new WebSocketServerCompressionHandler());
                //心跳相关
                if(settings.getHeartBeatCallBack()!=null){
                    pipeline.addLast(new IdleStateHandler(settings.getReadIdleTime(),settings.getWriteIdleTime(),settings.getAllIdleTime()));
                    pipeline.addLast(new NettyHeartBeatHandler(settings.getHeartBeatCallBack()));
                }
                //协议
                pipeline.addLast("protocolHandler", new WebSocketServerProtocolHandler(path, null));

//                pipeline.addLast("log-handler", new ChannelInboundHandlerAdapter() {
//                    @Override
//                    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
//                        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
//                            System.out.println("✅ WebSocket 握手成功！客户端: " + ctx.channel().remoteAddress());
//                        }
//                        super.userEventTriggered(ctx, evt);
//                    }
//
//                    @Override
//                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
////                        System.out.println("收到消息类型: " + msg.getClass().getSimpleName());
//                        super.channelRead(ctx, msg);
//                    }
//                });
                socketChannel.pipeline().addLast(new SessionHandler(serverNode));
                //消息解析
                pipeline.addLast(new WebsocketClientMsgCodec(settings.getMsgProtoc()));
////                //TODO 过滤器执行，比如检查cmd是否正确，某些cmd需要认证后才能访问等
//                socketChannel.pipeline().addLast(new GateWayLifeCycleHandler(serverNode));
//                //转发给broker
//                socketChannel.pipeline().addLast(new TcpGateWayForwarding(brokerManager));
                //消息分发
                pipeline.addLast(new ClientMsgDispatcherHandler(serverNode));
            }
        });
    }


    @Override
    public Integer serverPort() {
        return port;
    }

    @Override
    public void setServerPort(Integer port) {
        this.port = port;
    }
}
